#pragma once
#include <boost/smart_ptr.hpp>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include "../xpt/xptServer.h"

class LMWorkerProxy;
class LMContext;
class LMMaster
{
public:
	LMMaster(boost::shared_ptr<LMContext> config);
	virtual ~LMMaster();

	bool isLoggedin();
	void run();

	typedef struct  
	{
		uint8 algorithm;
		uint8 merkleRoot[32];
		uint8 prevBlockHash[32];
		uint32 version;
		uint32 nonce;
		uint32 nTime;
		uint32 nBits;
		// primecoin specific
		uint32 sieveSize;
		uint32 sieveCandidate; // index of sieveCandidate for this share
		uint8 fixedMultiplierSize;
		uint8 fixedMultiplier[201];
		uint8 chainMultiplierSize;
		uint8 chainMultiplier[201];
		// protoshare specific
		uint32 nBirthdayA;
		uint32 nBirthdayB;
		// riecoin specific
		uint8  riecoin_nOffset[32];
		// gbt stuff
		uint8 merkleRootOriginal[32];
		uint32 userExtraNonceLength;
		uint8 userExtraNonceData[16];
	}xptShareToSubmit_t;

	void foundShare(xptShareToSubmit_t* xptShareToSubmit);
	void submitShare(minerRiecoinBlock_t* block, uint8* nOffset);

protected:
	void login();
	void processLoop();
	void workerAccepter();
	void xptMiner_getWorkFromXPTConnection();
	void processPacket_authResponse();
	void processPacket_blockData1();
	void processPacket_shareAck();
	void processPacket_message();
	void processPacket_ping();
	void getDifficultyTargetFromCompact(uint32 nCompact, uint32* hashTarget);
	void sendShare(xptShareToSubmit_t* xptShareToSubmit);
	void sendPing();
	void updateWorkToAllWorkers();

protected:
	boost::shared_ptr<LMContext> _context;

	boost::mutex _workersMutex;
	std::vector<boost::shared_ptr<LMWorkerProxy>> _workers;

	boost::shared_ptr<boost::thread> _workerAcceptThr;
	boost::asio::io_service _ioSrv;
	boost::shared_ptr<boost::asio::ip::tcp::socket> _socketToPool;
	
	xptPacketbuffer_t* _xptSendBuffer; // buffer for sending data
	xptPacketbuffer_t* _xptRecvBuffer; // buffer for receiving data
	
	bool _isLoggedin;
	uint32	_algorithm;
	
	boost::mutex _blockWorkInfoMutex;
	xptBlockWorkInfo_t _blockWorkInfo;
	bool _hasWorkData;

	boost::mutex _shareSubmitQueueMutex;
	simpleList_t* _list_shareSubmitQueue;

	boost::posix_time::ptime _nextPingTime;
};
